<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>防抖节流</title>
		<style type="text/css">
			p {
				width: 200px;
				height: 200px;
				background-color: #f00;
			}

			div {
				width: 200px;
				height: 200px;
				background-color: #0f0;
				position: relative;
				top: -50px;
				left: 50px;
				background-color: #f00;

			}

			div:hover {
				/* width: 400px;
					height: 400px; */
			}
		</style>
	</head>
	<body style="height: 3000px;">
		<button>btn</button>
		<p style="display: none;">666666</p>
		<div style="background-color: red;">dddd</div>
		<script type="text/javascript">
			let oBtn = document.querySelector('button')
			let oBox = document.querySelector('div')
			
			//防抖 节流    降低 高频事件函数的触发频率
			oBtn.addEventListener('click',function(){
				console.log(666);
				// oBox.style.left = '200px'
				// oBox.style.transform = 'translateX(200px)'
			})
			
			// timer un      !timer true   fn会执行   clear    timer=1   500毫秒之后 timer = null
			//    timer 1  !timer  false  fn不执行  clear 1     500毫秒之后 timer = null
		
			// function debuunce(fn,wait){
			// 	let timer;
			// 	return function(e){
			// 		if(!timer){
			// 			fn.call(this,e)
			// 		}
			// 		clearTimeout(timer)
			// 		timer = setTimeout(function(){
			// 			timer=null
			// 		},wait)
			// 	}
			// }
			//非立即执行
			// function debuunce(fn, wait) {
			// 	let timer;
			// 	return function(e) {
			// 		let that = this
			// 		clearTimeout(timer)
			// 		timer = setTimeout(function() {
			// 			fn.call(that, e)
			// 		}, wait)
			// 	}
			// }
			
			//  time  un     !timer  true  fn执行  timer = 1  2000后  timer=nll
			//  timer = 1   !timer  false\
			///   timer=nll 
			// //节流 立即执行版本
			// function throttle(fn,wait){
			// 	let timer;
			// 	return function(){
			// 		let that = this
			// 		let arg = arguments
			// 		if(!timer){
			// 			fn.apply(that,arg)
			// 			timer = setTimeout(function(){
			// 				timer = null
			// 			},wait)
			// 		}
			// 	}
			// }

			//节流 非立即执行版本 
			// function throttle(fn,wait){
			// 	let timer;
			// 	return function(e){
			// 		console.log(1111111111111);
			// 		let that = this
			// 		if(!timer){
			// 			timer = setTimeout(function(){
			// 				console.log(e);
			// 				timer = null
			// 				fn.apply(that,[e])
			// 			},wait)
			// 		}
			// 	}
			// }

			

			/*
			防抖  节流  回流 重绘
			
			一.改变函数内部 this 指
			 apply bind call
			 1.apply
			 参数第一个this，后面用数组
				fn.apply(obj,[5,6,7])
			 2.call
			 参数第一个this，第二位之后传递的参数
				fn.call(obj,5,6,7)
			 3.bind
			 参数第一个this，第二位传递的参数，但是此函数调用，不会马上执行，返回值是一个函数
				fn.bind(obj)
				
				注意   apply  call 改变this指向同时会执行 函数   bind 改变this指向不会执行 会返回一个新的函数
			二.防抖节流：  降低  高频事件  的触发频率
				1.debounce(防抖)和throttle(节流)的定义  1
				防抖:触发高频事件后n秒内函数只会执行一次，如果n秒内高频事件再次被触发，则重新计算时间。
				节流:高频事件触发，但在n秒内只会执行一次，所以节流会稀释函数的执行频率。
				口语版:
				防抖就是只有当小明连续10天不捣蛋时，小明爸爸才给他零花钱。如果在这10天内小明捣蛋了，
				 那么重新计算，直到满足了10天不捣蛋的条件，小明爸爸才给零花钱。一年下来小明居然只
				 拿到了5次零花钱，你说气人不？
				
				节流就是无论小明捣蛋不捣蛋，小明爸爸每隔10天都给小明零花钱。一年下来，小明拿到了36次零花钱。
				防抖是有条件的周期动作，而节流是没有条件的周期动作。
				书面版:
				
				
				2.防抖和节流解决什么问题x`
				在进行resize、scroll、keyup、keydown、mousedown、mousemove等事件操作时，如果事件处理函数调用
				的频率无限制，会加重浏览器的负担，容易导致页面卡顿等影响用户的体验；
				这时就可以通过debounce(防抖)和throttle(节流)函数来限制事件处理函数的调用频率，
				提升用户的体验，同时又不影响实际的效果。
				
				3.防抖和节流的应用场景
				防抖
				1.登录、发短信等按钮避免用户点击太快，以致于发送了多次请求，需要防抖。
				2.调整浏览器窗口大小时，resize 次数过于频繁，造成计算过多。
				3.文本编辑器实时保存，当无任何更改操作一秒后进行保存。
				4.DOM 元素的拖拽功能实现。
				5.计算鼠标移动的距离。
				6.Canvas 模拟画板功能。
				7.搜索。
				节流
				1.scroll 事件，每隔一秒计算一次位置信息等。
				2.浏览器播放事件，每个一秒计算一次进度信息等。
				3.input框实时搜索并发送请求展示下拉列表，每隔一秒发送一次请求 (也可做防抖)。
				
				4.防抖
					非立即执行版：短时间内多次触发函数，只会执行最后一次，中间的不执行
					立即执行版：短时间内多次触发函数，只会执行第一次，中间的不执行
				  节流
					如果一直不断地触发函数，它会按照指定的时间执行函数
				
				5.重绘 回流
				① 浏览器的渲染过程
				解析HTML，生成DOM树，解析CSS，生成CSSOM树
				将DOM树和CSSOM树结合，生成渲染树(Render Tree)
				Layout(回流):根据生成的渲染树，进行回流(Layout)，得到节点的几何信息（位置，大小）
				Painting(重绘):根据渲染树以及回流得到的几何信息，得到节点的绝对像素
				Display:将像素发送给GPU，展示在页面上。（这一步其实还有很多内容，比如会在GPU将多个合成层合并为同一个层，
				并展示在页面中）
				
				前面我们通过构造渲染树，我们将可见DOM节点以及它对应的样式结合起来，可是我们还需要计算它们在
				设备视口(viewport)内的确切位置和大小，这个计算的阶段就是回流
				
				最终，我们通过构造渲染树和回流阶段，我们知道了哪些节点是可见的，以及可见节点的样式和具体的几何信息(位置、大小)，
				那么我们就可以将渲染树的每个节点都转换为屏幕上的实际像素，这个阶段就叫做重绘节点。
				
				
				何时发生回流	
				添加或删除可见的DOM元素
				元素的位置发生变化
				元素的尺寸发生变化（包括外边距、内边框、边框大小、高度和宽度等）
				内容发生变化，比如文本变化或图片被另一个不同尺寸的图片所替代。
				页面一开始渲染的时候（这肯定避免不了）
				浏览器的窗口尺寸变化（因为回流是根据视口的大小来计算元素的位置和大小的）
				
				回流必定触发重绘
				https://zhuanlan.zhihu.com/p/52076790
			*/
		</script>
	</body>
</html>